from django.shortcuts import render
from rest_framework.decorators import action
from rest_framework .views import APIView

from goods.models import SKU
from goods.serializers import SKUModelSerializer
from .constansts import USER_ADDRESS_COUNTS_LIMIT, USER_HISTORIES
from .models import User, Area
from rest_framework.response import Response
# Create your views here.
import random
from django_redis import get_redis_connection
from celery_tasks.sms .tasks import send_sms_code
from rest_framework.generics import CreateAPIView, RetrieveAPIView, UpdateAPIView, ListAPIView
from rest_framework.permissions import IsAuthenticated
from .serializers import CreatUserSerializer, UserSerializer, EmailSerializer, AreasSerializer, SubsAreasSerializer, \
    UserAddressSerializer, AddressTitleSerializer, HistoriesSerializer
from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
from rest_framework_extensions.cache.mixins import CacheResponseMixin

""""
1.用户是否存在 
2.手机号是否存在
3.实现短信验证码的发送功能：Django没有这个功能，第三方应用：云通讯 的应用实现发送短信的功能


4.实现整体的用户注册功能


"""

class  UsernameCountView(APIView):
    def get(self, request, username):
        """
        验证用户名是否存在 1 0  返回的是这个用户的 count  --- 数量
        :param request:
        :param username:
        :return:
        """
        #  查询 用户名的数量
        count = User.objects.filter(username=username).count()
        # print(count)

        data = {
            'count': count,
            'username': username,
        }
        #  响应 出去
        return Response(data=data)


class MobileCountView(APIView):
    def get(self, request, mobile):
        """
        验证手机号是否1存在 1 0  返回的是这个用户的 count  --- 数量
        :param request:
        :param username:
        :return:
        """
        #  查询 手机号的数量
        count = User.objects.filter(mobile=mobile).count()
        # print(count)

        data = {
            'count': count,
            'mobile': mobile,
        }
        #  响应 出去
        return Response(data=data)

from celery_tasks.sms import tasks


class SMSCodeView(APIView):
    """
    发送短信验证码的
    1. 生成和发送短信验证码: 数字  个数 4,6  随机
    2. 保存短信验证码
    3. redis pipeline的使用
    4. 检查是否在60s内有发送记录
    5. Celery异步发送短信
    状态码： 后端来看 用来识别请求是否成功的
    200 202 201
    404 400
    Access to XMLHttpRequest at
    'http://192.168.216.14:8001/sms_codes/18867455861/' from origin 'http://127.0.0.1:8080'
    has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
    header is present on the requested resource.
    已被CORS策略阻止
    pip install django-cors-headers

    CORS策略： 跨域访问   浏览器为了用户的安全
    2个不同的服务器 或者是2个不同的服务地址 存在的相互调用

    """

    def get(self, request, mobile):
        redis_conn = get_redis_connection('verify_codes')
        #  判断是否在60s内有发送记录
        send_flag = redis_conn.get('send_flag_%s' % mobile)
        # send_flag = redis_conn.get(f'send_flag:{mobile}')
        if send_flag:
            return Response({'message': '发送短信验证码过于频繁'})

        #  生成和发送短信验证码
        sms_code = '%06d' % random.randint(0, 999999)
        # sms_code = f'{random.randint(0, 999999):06d}'  # 这两步改成了格式化赋值的办法，结构清晰点
        print(f'我是验证码：{sms_code}')
        #  保存短信验证码： 和手机号对应  Redis中的string  手机号：短信验证码
        # redis_conn =  get_redis_connection('verify_codes')
        #  redis pipeline的使用: 管道的方法：可以把要做的操作语句先准备好，然后统一执行
        #  保存2个东西： 记录--发送的记录，短信验证码
        pl = redis_conn.pipeline()
        #  短信验证码 --保存的时候设置过期时间 秒
        pl.setex('sms_%s' % mobile, 300, sms_code)
        # pl.setex(f'sms_code:{mobile}', 300, sms_code)
        #  记录--发送的记录 60 秒  设置为1
        pl.setex('send_flag_%s' % mobile, 60, 1)
        # pl.setex(f'send_flag:{mobile}', 60, 1)
        #  执行操作
        pl.execute()
        #  调用发送短信验证码 ---
        tasks.send_sms_code(mobile, sms_code)
        # send_sms_code(mobile,sms_code)
        return Response({'message': 'OK'})

# 实现注册功能: 把前端发送过来的数据进行验证，然后保存--- 目的： 保存到数据库中
# from rest_framework.generics import CreateAPIView

class UserView(CreateAPIView):
    #  指定序列化器：  利用序列化器 使用数据的获取并检验和保存 再序列化返回
    serializer_class = CreatUserSerializer

# UserSerializer
class UserDetailView(RetrieveAPIView):
    """
    get的请求方法
    """
    serializer_class = UserSerializer
    # queryset =  当前登录的用户相关信息
    def get_object(self):

        return self.request.user


class EmailView(UpdateAPIView):
    """
    邮箱保存功能--- 和当前登录的用户是对应关系
    实现保存邮箱的数据
    返回数据
    """
    serializer_class = EmailSerializer

    # 添加用户认证权限
    # permission_classes = (IsAuthenticated,)   # 这句是课程中得错误案例，真就照搬啊
    # queryset =  当前登录的用户相关信息
    def get_object(self):
        return self.request.user


class VerifyEmailView(APIView):
    """
    邮箱验证
    """

    def get(self, request):
        """
        目的是验证邮件成功：
        token值
        :param request: 在请求中获取  query_params() DRF
        :return:  验证数据  如果通过了 就修改邮箱的验证状态
        """
        token = request.query_params.get('token')
        print(token)
        if not token:
            return Response({'message': '缺少token'}, 400)
        # 验证：----  check_verify_token

        user = User().check_verify_token(token)
        if user is None:
            return Response({'message': '链接验证失败'}, 402)

        else:
            # 验证成功
            user.email_active = True
            user.save()
        return Response({'message': 'OK'})


class AreasViewSet(CacheResponseMixin,ReadOnlyModelViewSet):
    """
    查询省市区的数据：
    查询省的数据 用的语法 是和查询市或者县的语法是不一样的
    因为这个查询的接口只有一个 而返回的数据是要有省的或者是市的
    所以 用视图集来实现 区分不同的请求方法：
    ReadOnlyModelViewSet--- 实现查询所有(list)，和单个或者是一部分
    """

    # queryset = Area.objects.all()
    def get_queryset(self):
        """
        通过查询集的方法
        :return:  GET  ---- 查询所有 --- 查询单个
        """
        #  判断一下 请求方法：通过不同请求方法来识别返回不同的数据
        # self.action --- 获取不同的请求方法
        if self.action == 'list':
            #  查询省的数据
            return Area.objects.filter(parent=None)
        else:
            return Area.objects.all()

    def get_serializer_class(self):
        """
        提供序列化器的方法
        :return:
        """
        if self.action == 'list':
            #  序列化省的数据
            return AreasSerializer
        else:
            # 利用自关联查询市，县的数据
            return SubsAreasSerializer


class AddressViewSet(ModelViewSet):
    """
    用户收货地址功能实现
    """
    permission_classes = (IsAuthenticated,)
    serializer_class = UserAddressSerializer

    def get_queryset(self):
        #获取当前登录的用户地址 然后进行序列化 返回
        return self.request.user.addresses.filter(is_deleted=False)

    def list(self,request,*args,**kwargs):
        queryset = self.get_queryset() #指定查询的数据
        ser = self.get_serializer(queryset,many=True)
        user = self.request.user
        return Response(
            {
                'addresses':ser.data,
                'limit':USER_ADDRESS_COUNTS_LIMIT,
                #当前用户的默认地址id
                'default_address_id':user.default_address_id
            }
        )

    def create(self,request ,*args,**kwargs):
        # 保存数据，检查用户地址数量的上限 不能超过20个
        #request.user————User模型类对象 .address
        count = request.user.addresses.count()
        if count > USER_ADDRESS_COUNTS_LIMIT :
            return Response({'massage':'地址保存已达上限'})
        return super().create(request,*args,**kwargs)
        pass
    # def destroy(self, request, *args, **kwargs):
    #     pass
    # def update(self, request, *args, **kwargs):
    #     pass
    """
    @action(methods=['get'],detail=False)
    def lists(self,request):
        book =  BookInfo.objects.filter(image=None)
        print(book)
        ser =  self.get_serializer(book,many=True)
        return Response(ser.data)

    """

    #  修改默认地址
    @action(methods=['put'], detail=True)
    def status(self, request, pk=None):
        # 获取当前要设置的用户地址
        address = self.get_object()
        request.user.default_address = address
        request.user.save()
        return Response({'message': 'OK'}, status=200)

    @action(methods=['put'], detail=True)
    def title(self, request, pk=None):
        """
        修改标题  ：序列化后  ---返回修改成功后的标题
        :param request:
        :param pk:
        :return:
        """
        #  要修改的数据
        address = self.get_object()
        ser = AddressTitleSerializer(instance=address, data=request.data)
        ser.is_valid(raise_exception=True)
        ser.save()
        return Response(ser.data)



class SavePassword(APIView):
    def put(self,request):
        ipassword = request.data['ipassword']
        password = request.data['password']
        password2 = request.data['password2']
        user_id = request.data['user_id']
        user = User.objects.get(id=user_id)
        if password != password2:
            raise Exception('两次密码输入不一致')
        if len(password) < 8 or len(password) > 20:
            raise Exception('密码最少8位，最长20位')
        user.check_password(ipassword)
        user.set_password(password)
        user.save()
        return Response(status=202)

#HistoriesSerializer
class SKUHistoriesView(CreateAPIView):
    """
    保存 --post
    查询的 --get
    """
    serializer_class = HistoriesSerializer
    permission_classes = (IsAuthenticated,)

    def get(self,request):
        """
        查询浏览记录
        """
        # 1.从Redis中查询出用户对应的商品id
        user_id = request.user.id
        redis_conn = get_redis_connection('history')
        history =  redis_conn.lrange('history_%s' % user_id,0,USER_HISTORIES)
        # print(history)
        # 2利用这个商品id 去查询模型类中的数据
        skus = []
        for sku_id in history:
            sku =  SKU.objects.get(id=sku_id)
            skus.append(sku)
        ser =  SKUModelSerializer(skus,many=True)
        # 3.返回数据--- JSON的数据 --- 序列化器
        return Response(ser.data)
